home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Very Best of Atari Inside
/
The Very Best of Atari Inside 1.iso
/
sharew
/
emulator
/
c64
/
artikel.txt
< prev
next >
Wrap
Text File
|
1994-10-17
|
22KB
|
384 lines
Wohl jeder, der sich etwas intensiver mit seinem Computer
beschäftigt hat, wird sich schon einmal geärgert haben, daß
ausgerechnet das Programm, das er gerne besitzen würde, auf
seinem Rechner nicht läuft. Besonders viel professionelle
Software ist z.B. für andere Betriebssysteme wie MS-DOS oder CP/M
zu erhalten. Da diese Systeme jedoch für andere Prozessoren als
den 68000 geschrieben sind, ist es eigentlich nicht möglich,
deren Programme auf dem Atari ST zu verwenden. Ganz ausweglos ist
die Situation nun aber auch nicht. Für die oben genannten
Betriebssysteme gibt es inzwischen Emulatoren auf dem Markt, die
es ermöglichen, auch Programme, die für andere Prozessoren oder
Betriebssysteme geschrieben worden sind, auf dem ST laufen zu
lassen. Von diesen Programmen sind die MAC-Emulatoren besonders
hervorzuheben. Da der Macintosh wie der ST ebenfalls mit einen
68000-Prozessor arbeitet, ist es in diesem Fall möglich, durch
ein entsprechendes Programm nicht nur das Macintosh-
Betriebssystem auf dem ST zu implementieren, sondern dabei auch
noch eine größere Geschwindigkeit im Programmablauf zu erreichen,
als dies auf dem "Original" MAC-System der Fall ist. Die Ursache
hierfür liegt darin, daß der 68000 beim ST höher getaktet ist,
als im Macintosh. Leider dürfte diese Art von Emulatoren ein
Sonderfall bleiben, denn die bekanntesten Betriebssysteme laufen
nun einmal nur auf Rechnern, die keinen Prozessor der 68000-
Familie benutzen. In diesem Fall bleibt als Ausweg nur die
Software-Emulation des entsprechenden Prozessors. Der
Geschwindigkeitsverlust, der dabei auftritt, läßt sich leider
nicht vermeiden. Allerdings kann man bei entsprechender
Programmierung trotzdem recht akzeptable Geschwindigkeiten
erreichen, auch wenn man dieses nicht jedem auf dem Markt
befindlichen Emulator anmerkt.
Als Atari- und C64-Besitzer habe ich mich damit beschäftigt, das
Betriebssystem des C64 so gut wie möglich auf dem ST zu
implementieren. Für die Spiele-Freaks heißt das aber leider
nicht, daß nun der ST in der Lage ist, C64-Spiele zu verarbeiten.
Dazu ist der Aufbau der beiden Computer zu verschieden. Dennoch
läßt sich bis auf einige spezielle Fähigkeiten des C64 ein
brauchbarer Emulator entwickeln. Was man bei der Programmierung
eines solchen Emulatorprogramms beachten sollte, wird Gegenstand
des Artikels sein. Da dieser Teil Kenntnisse in Assembler-
Programmierung voraussetzt, dürfte er vor allem für Assembler-
Programmierer interessant sein. Außerdem möchte ich kurz ein paar
Features des C64-Emulators beschreiben. Konkretere Hinweise
finden sich auf der Leserservice-Diskette, auf der sich der
Emulator befindet.
Bevor man sich um die Implementierung eines konkreten
Betriebssystems kümmern kann, geht es erst einmal darum, sich
detaillierte Informationen über den zu emulierenden Prozessor zu
besorgen. (Dabei setze ich natürlich voraus, daß man die
Programmierung des 68000 gut beherrscht.) Um sich näher mit dem
eigentlichen Betriebssystem beschäftigen zu können, muß
schließlich erst einmal die Emulation für den entsprechenden
Prozessor stehen. Für die bekanntesten Prozessoren, wie im Fall
des C64 für den 6502, ist es kein Problem, an die entsprechende
Literatur zu kommen. Wichtig sind vor allem Informationen über
die Behandlung der Flags des Prozessors bei den verschiedenen
Befehlstypen sowie eine Beschreibung eventueller Besonderheiten
des Prozessors. Zu beachten ist, daß z.B. das Carry-Flag durchaus
nicht in allen Prozessoren die gleiche Bedeutung hat. Gerade der
6502 hat hier seine Besonderheit. Im günstigsten Fall hat man
schon einmal mit dem zu emulierenden Prozessor gearbeitet, was
sich im weiteren Verlauf der Programmierung als großer Vorteil
erweisen wird.
Bei der eigentlichen Programmierung des Emulators spielt die
Geschwindigkeit der Befehlsauswertung eine besonders große Rolle.
Da der 68000 mit den Befehlscodes des 6502 überhaupt nichts
anfangen kann, muß jeder Opcode interpretiert werden, ähnlich wie
es ein BASIC-Interpreter mit einem BASIC-Programm macht. Für
jeden 6502-Code muß eine Routine in 68000-Assembler entwickelt
werden, die Aktionen vornimmt, die dem entsprechenden 6502-Befehl
entsprechen. Hierin liegt auch der Grund, warum es nicht möglich
ist, mit einem Software-Emulator die gleiche Geschwindigkeit zu
erreichen, wie sie das System besitzt, das emuliert wird. Obwohl
der 68000 mit 8 MHz getaktet ist und der 6510 im C64 mit nur
knapp 1 MHz, bedeutet die Interpretation der Befehlsbytes einen
Verlust an Geschwindigkeit. Die eigentliche Bearbeitung der
einzelnen Opcodes in den entsprechenden Routinen kann jedoch
durchaus schneller vom 68000 ausgeführt werden, als vom 6502. So
benötigt der C64-Emulator zum Setzen des Carry-Flags 4 Taktyklen,
der 6502 braucht 2 Taktzyklen. Rechnet man diese Angaben auf die
Taktfrequenzen der beiden Prozessoren um, so schneidet der 68000
deutlich besser ab. Allerdings muß nun noch die Zeit addiert
werden, die der Emulator benötigt, bis er die Adresse der Routine
zum Setzen des Flags ermittelt hat. Dieser Vorgang nimmt jedoch
so viel Zeit in Anspruch, daß der 6502 schließlich doch der
Schnellere ist. Da die Taktfrequenz neuerer Prozessortypen immer
weiter steigt, wird es wohl nur eine Frage der Zeit sein, bis es
möglich ist, einen 8 Bit-Prozessor mindestens mit der
Geschwindigkeit zu emulieren, mit der dieser Prozessor
normalerweise betrieben wird.
Nun wiederholt sich der Vorgang der Interpretation des folgenden
Befehlsbytes natürlich bei jedem neuen 6502-Opcode. Deshalb ist
es gerade an dieser Stelle besonders wichtig, eine möglichst
schnelle Auswertung des nächsten Befehlsbytes zu erreichen. Spart
man hier nur einen Taktzyklus ein, so steigt die Geschwindigkeit
der Emulation bereits merklich. Wie kann nun das nächste
Befehlsbyte ausgewertet werden? Im allgemeinen wird hierzu dieses
Byte in ein Datenregister geladen und dann die Adresse der
zugehörigen Emulationsroutine aus diesem Byte berechnet. Dies
kann z.B. durch den folgenden Algorithmus geschehen:
LOOP: CLR D0
MOVE.B (A0)+,D0
ASL #2,D0
MOVE.L (A1,D0),A0 Algorithmus 1
JSR (A0)
BRA LOOP
Geht man davon aus, daß A0 auf das nächste Befehlsbyte im 6502-
Adreßraum zeigt und A1 den Anfang einer Tabelle mit
Sprungadressen auf die entsprechenden Emulationsroutinen enthält,
würde obiges Programmfragment den Anforderungen gerecht.
Allerdings läßt die Geschwindigkeit der Interpretation noch viel
zu wünschen übrig. Um eine höhere Geschwindigkeit zu erreichen,
kann man den ASL-Befehl durch zwei ADD-Befehle ersetzen und die
obige Routine für jeden zu emulierenden Opcode neu programmieren,
was dann so aussehen könnte:
CLR D0
MOVE.B (A0)+,D0
ADD D0,D0
ADD D0,D0
MOVE.L (A1,D0),A0 Algorithmus 2
JMP (A0)
In diesem Fall wird die nächste auszuführende Routine nicht mehr
als Unterprogramm angesprungen, so daß man nicht mit RTS zu einer
übergeordneten Interpretationsroutine zurückkehren kann. Eben aus
diesem Grund muß sich der obige Programmteil am Ende jeder
Emulations-Unterroutine befinden, also für jeden Opcode einmal im
Programm vorhanden sein. Dadurch wird das Emulatorprogramm zwar
länger, dafür aber deutlich schneller, da der Aufruf und die
Rückkehr aus einem Unterprogramm besonders viel Zeit benötigt.
Und Geschwindigkeit ist für einen Software-Emulator das höchste
Gebot! Darüber hinaus hat man auf dem ST genug Speicherplatz, um
bei einem Emulator für einen Prozessor mit nur 64K Adreßraum
nicht sparen zu müssen.
Der oben dargestellte Algorithmus 2 findet sich in ähnlicher Form
in allen mir bekannten Software-Emulatoren wieder. Lassen sie uns
einmal ein wenig rechnen: Die Ausführungsgeschwindigkeit für
diesen Algorithmus beträgt 46 Taktzyklen. Der 6502 ist
normalerweise mit 1MHz getaktet, der ST mit 8MHz. Allein die
Interpretation eines Befehlsbytes würde demnach eine Zeit
verbrauchen, die 46/8 6502-Zyklen entspricht, also fast 6 6502-
Zyklen. Da die kürzesten 6502-Befehle 2 Taktzyklen (bezogen auf
den 6502) brauchen, würde nur die Auswertung des nächsten Befehls
durch den Emulator schon extrem viel Zeit verschlingen. Das
Prinzip, das in Algorithmus 2 zur Interpretation verwendet wurde,
kann jedoch nicht mehr entscheidend verkürzt werden. Ursprünglich
arbeitet auch mein C64-Emulator mit einem vergleichbaren
Algorithmus.
Ist man allerdings bereit, 64K Speicherplatz mehr für den
Emulator zu opfern, was beim ST normalerweise möglich ist, so
kann man die so zeitkritische Befehlsinterpretation durch eine
völlig andere Programmierung deutlich beschleunigen. Hier die
Routine, wie sie in meinem Emulator verwendet wird:
MOVE.B (A0)+,LBL+2(A1)
LBL: JMP $0(A1) Algorithmus 3
Auch hier ist A0 Pointer auf das nächste Befehlsbyte, A1 ist ein
spezieller Pointer in das 64K-Segment, in dem sich der Emulator
nun befindet. Nun ein paar Erklärungen zu Algorithmus 3, denn er
dürfte nicht so einsichtig sein, wie die ersten beiden. Im obigen
Fall wird das Befehlsbyte nämlich ohne irgendwelche weiteren
Berechnungen direkt zur Adreßbildung im darauffolgenden
Sprungbefehl verwendet. Hierzu am besten ein Beispiel. Nehmen wir
an, der nächste 6502-Opcode, auf den das Adreßregister A0 zeigt,
ist $EA. Dieses Byte wird nun als Displacement für den folgenden
Sprungbefehl benutzt, wobei sich das Programm selbst verändert.
Direkt vor dem Sprung sieht der Sprungbefehl dann also
folgendermaßen aus:
JMP $EA00(A2)
Das 6502-Befehlsbyte bildet das Hi-Byte für das Displacement, das
Lo-Byte ist immer Null. Auf diese Art und Weise spart man sich
jegliche Adreßberechnung, da die Sprungadresse auf die passende
Routine nicht mehr einer Tabelle entnommen wird, wie es bei den
ersten beiden Algorithmen der Fall ist. Allerdings muß nun jede
Routine zur Behandlung der Opcodes in genau einer Page Abstand
hinter dem Beginn der vorherigen Routine anfangen, da das Lo-Byte
des Displacements immer Null ist. So kommt es auch, das für diese
Art der Emulation 64K Speicherplatz benötigt werden, nämlich für
jeden Opcode des 6502 256 Bytes. Die Ausführungszeit von
Algorithmus 3 beträgt nur noch 30 Taktzyklen. Er ist also um 50%
schneller als Algorithmus 2. Dieser Geschwindigkeitszuwachs macht
sich deutlich bemerkbar, denn er schlägt ja bei jedem 6502-Opcode
neu zu Buche.
Soweit das Wichtigste zur Interpretation der Befehlsbytes des
6502. Ist dieses Problem gelöst, so muß man sich als Nächstes
darum kümmern, wo die Register des zu emulierenden Prozessors
"aufbewahrt" werden können. In unserem Fall ist diese Frage recht
einfach zu beantworten. Der 6502 hat drei Register (Akkumulator,
X- und Y-Register) sowie einen 8-Bit-Stackpointer und den
Programmzähler. Der 68000 besitzt insgesamt 15 Register, wenn man
A7 als Stackpointer einmal außer Acht läßt. Es ist somit keine
Kunst, diese Register in Daten- bzw. Adreßregistern des 68000
unterzubringen. Für Stackpointer und Programmzähler wird jeweils
ein Adreßregister, für die anderen 6502-Register werden drei
Datenregister verwendet, in denen nur das Lo-Byte genutzt wird.
Schließlich muß das Prozessorstatusregister des 6502 auch noch
irgendwo untergebracht werden. Es ist im allgemeinen nicht
möglich, einfach die Flags des 68000 zu verwenden, da sich deren
Verwendung von der beim 6502 geringfügig unterscheidet. Darüber
hinaus hat der 68000 im Gegensatz zum 6502 z.B. kein Dezimalflag.
Bei den meisten arithmetischen Operationen besteht in der
Behandlung der Flags jedoch kein Unterschied. Es empfiehlt sich,
die Flags in einem weiteren Datenregister unterzubringen und nur
bei Bedarf in das CCR-Register des 68000 zu übertragen.
Schließlich wird des Prozessorstatusregister nicht von jedem
Befehl beeinflußt. Nachdem bei Rechenoperationen die Flags im CCR
entsprechend gesetzt worden sind, werden sie dann wieder in das
reservierte Datenregister übertragen.
Durch die beschriebene Verwendung der Register bleiben noch
einige Register dem Programmierer zur Verfügung. Sie können dann
Daten aufnehmen, die während der Emulation ständig zur Verfügung
stehen sollen, wie z.B. ein Pointer auf den 64K Adreßraum des
6502 sowie auf die 64K, die für den Emulator reserviert sind, und
in dem sich die Emulationsroutinen für die einzelnen Opcodes des
6502 befinden. Prinzipiell ist es natürlich auch möglich, die
Registerinhalte des 6502 im Speicher abzulegen. Allerdings dauern
Zugriffe auf den Speicher verhältnismäßig lange, so daß man keine
brauchbare Geschwindigkeit mehr erzielen könnte.
Will man Prozessoren emulieren, die mehr Register aufweisen, als
der 6502 sie besitzt, so muß man die Aufteilung neu überdenken.
Dies ist übrigens bei den meisten anderen Prozessoren der Fall,
z.B. beim 8080, Z80 und 8086. Man sollte jedoch durch geschickte
Wahl der Registerbelegung stets dafür sorgen, daß absolute
Zugriffe auf den Speicher möglichst vermieden werden, da sie
besonders zeitaufwendig sind. Beim C64-Emulator konnten direkte
Zugriffe auf den Speicher vollkommen umgangen werden. Hier wird
nur über Adreßregister auf den Adreßraum des 6502-Prozessors
zugegriffen.
Will man mit dem 68000 einen 8 Bit-Prozessor emulieren, so sind
einige Adressierungsarten und Befehle recht leicht
nachzuvollziehen, andere stellen jedoch Probleme dar, besonders
dann, wenn es darum geht, eine möglichst schnelle Ausführungszeit
zu erzielen. Ich möchte hier als Beispiel die absolute
Adressierung des 6502 anführen. Eigentlich kein Problem, sollte
man meinen. Aber dennoch muß man hier vorsichtig sein. Wie sie
sicher wissen, kann der 68000 auf 16 Bit-Worte nur dann
zugreifen, wenn sie auf geraden Speicheradressen stehen. Verstöße
gegen diese Regel führen zu einem Adreßfehler, der sich in drei
Bomben personifiziert. Bei Programmen, die für diesen Prozessor
geschrieben sind, liegen die Befehlsworte und absoluten Adressen
deshalb natürlich immer auf geraden Adressen. Bei 8 Bit
Prozessoren sieht die Sache jedoch ganz anders aus. Die oben
angeführte Einschränkung für absolute Adressen besteht hier
nicht. Es kann also ohne Weiteres passieren, daß die absolute
Adresse, die auf einen Sprungbefehl des 6502 folgt, auf einer
ungeraden Adresse liegt. Somit ist es nicht möglich, die Adressen
für die absolute Adressierung mit einem einzigen Befehl aus dem
6502-Adreßraum in ein Register des 68000 zu holen. Solche
Adressen müssen hier grundsätzlich in zwei einzelne Bytes
aufgespalten werden. Darüber hinaus existiert noch ein weiteres
Ärgernis. Im Gegensatz zum 68000 werden bei 8 Bit Prozessoren
absolute Adressen mit den Lo-Byte zuerst im Speicher abgelegt.
Bevor man eine solche Adresse verwenden kann, müssen also erst
die beiden Adreßbytes in die richtige Reihenfolge gebracht
werden. Mit folgender Routine könnte dann die absolute Adresse
aus dem Speicher in ein Datenregister geholt werden:
MOVE.B (A0)+,D0
ASL #8,D0 Algorithmus 4
MOVE.B (A0)+,D0
ROR #8,D0
Die beiden Bytes für die absolute Adresse werden hier einzeln aus
dem Speicher geholt und durch Schieben und Rotieren in die
richtige Reihenfolge gebracht. So weit, so gut. Leider brauchen
Schiebe- und Rotierbefehle relativ viel Zeit. Algorithmus 4 mag
zwar leicht zu durchschauen sein, benötigt jedoch 58 Taktzyklen.
Dies ist besonders ungünstig, wenn man bedenkt, daß die absolute
Adressierung relativ häufig vorkommt. Ist man jedoch bereit, ein
Adreßregister zu opfern, so kann man durch eine völlig
andersartige Programmierung einen großen Geschwindigkeitsvorteil
erlangen:
MOVE.B (A0)+,-(A2)
MOVE.B (A0)+,-(A2) Algorithmus 5
MOVE (A2)+,D0
In Algorithmus 5 zeigt A2 auf eine beliebige gerade Adresse im
Speicher, an der die beiden Bytes zu einem Wort zusammengesetzt
und anschließend nach D0 übertragen werden. Diese etwas
unkonventionelle Art der Programmierung mag zwar umständlich
erscheinen, sie kommt dafür jedoch mit nur 32 Zyklen aus, denn
Schiebe- und Rotierbefehle entfallen nun völlig. Leider ist es
nicht möglich, den Stackpointer, also A7, so zu benutzen, wie in
diesem Beispiel A2. Der Stackpointer wird nämlich grundsätzlich
um ein Wort, also zwei Bytes, erhöht oder erniedrigt, auch wenn
Byteoperationen durchgeführt werden, so daß er sich nicht an
Stelle eines anderen Adreßregisters benutzen läßt.
Die obige Problematik stellt nur eines von vielen Problemen dar,
die man bei der Emulation eines 8 Bit Prozessors zu bewältigen
hat, wenn man um jeden Taktzyklus kämpfen muß.
Ist nun endlich die eigentliche Emulation des Prozessors
fertiggestellt, wobei natürlich fraglich ist, wieviele Fehler sie
noch enthält, muß man als nächstes sein Augenmerk auf die
Implementation des Betriebssystems richten. Schließlich ist es
das erste und wichtigste Programm, das man zum Laufen bringen
muß. Läuft das Betriebssystem unter dem Emulator einwandfrei, so
kann man davon ausgehen, daß sich kaum noch Fehler im Programm
befinden, da alle Befehle des emulierten Prozessors irgendwann
einmal ausgeführt werden dürften.
Nicht jedes Betriebssystem läßt sich gleich gut auf einen anderen
Computer übertragen. Das Betriebssystem des C64 läßt in dieser
Hinsicht einiges zu Wünschen übrig. Im günstigsten Fall gibt es
für jede wichtige Funktion, die vom System erledigt werden soll,
also insbesondere um die Behandlung der Ein- und Ausgabe, eine
Funktionsnummer oder einen Sprungvektor. Beim C64 gibt es zwar
eine solche Liste von Sprungvektoren, nur ist sie leider nicht so
vollständig, wie man es gerne hätte. Besser sieht es da bei CP/M
und MS-DOS aus. Hier gibt es weitaus mehr Funktionen als beim
C64, so daß eine Emulation erleichtert wird. Dies liegt natürlich
daran, daß diese beiden System ohnehin für den Einsatz auf
unterschiedlichen Computern vorgesehen sind, was beim C64 ja
nicht unbedingt der Fall ist. Welches System man auch immer
emulieren will, alle Aufgaben die über solche Vektoren oder
Funktionsnummern aufgerufen werden, müssen vom Emulator überwacht
werden. Hierzu ein konkretes Beispiel: Für die Ausgabe von
Zeichen auf dem C64 existiert ein Sprungvektor BSOUT. Da die
Bildschirmdarstellung der Zeichen auf dem ST grundsätzlich anders
realisiert wird als auf dem C64, muß an dieser Stelle
eingegriffen werden. Die Ausgabe auf dem Bildschirm darf nicht so
erfolgen, wie es beim C64 geschehen würde, denn dann würde sich
auf dem Bildschirm des ST gar nichts tun. Sie muß in einer
eigenen Ausgaberoutine programmiert werden. Das gleiche gilt für
viele andere Funktionen des Betriebssystems auf dem C64.
Natürlich muß man darauf achten, daß die Register, die für den
Betrieb des Emulators wichtige Daten enthalten, nicht in den
eigenen Routinen verändert werden bzw. nur Daten erhalten, die
vom Betriebssystem des C64 erwartet werden. Die LOAD-Routine soll
z.B. das Ende des geladenen Programms als Rückgabewert in den
Indexregistern liefern.
Wie schon angesprochen, muß die Emulation durch geeignete
Programmierung so gestaltet werden, daß sie möglichst schnell
erfolgt. Neben entsprechender Programmierung des Emulators gibt
es noch weitere Möglichkeiten, die Geschwindigkeit von Programmen
auf dem ST zu erhöhen, besonders dann, wenn es sich nicht um
Programme handelt, die in GEM-Umgebung laufen. In diesem Fall ist
es nämlich möglich, Vektoren, wie den evnt_timer-Vektor des GEM
auf einen RTS-Befehl umzubiegen, so daß die zugehörigen Routinen,
die während eines Interrupts ausgeführt werden, nicht mehr
angesprungen werden. Dies hat unter anderem zur Folge, daß die
Uhr des Kontrollfelds nicht mehr läuft, wenn der Emulator aktiv
ist. Da man sie beim C64-Emulator ohnehin nicht benötigt, ist
dies aber kein Beinbruch. Der Lohn dafür ist eine erhöhte
Geschwindigkeit. Weiterhin kann es lohnenswert sein, die Maus
abzuschalten, oder besser noch alle Aktionen, die den
Tastaturprozessor betreffen, selbst zu übernehmen.
Zum Schluß möchte ich noch auf die Frage eingehen, inwieweit
überhaupt eine Kompatibilität, insbesondere zum C64, auf einem
anderen Computer zu erreichen ist. Überlegt man sich, was den C64
so erfolgreich gemacht hat, so sind dies in erster Linie die
unzähligen Spiele, die für diesen Computer existieren. Gerade
Spiele reizen die speziellen Fähigkeiten des C64 (Sprites,
Rasterzeilen-Interrupt, Timer) besonders aus. Da die Hardware des
ST keine Darstellung von Sprites erlaubt, und diese Grafikobjekte
nicht nur aus Zeitgründen unmöglich durch Software nachgebildet
werden können, ist die Emulation von Spielen also in Frage
gestellt. Weiterhin ist es aus Zeitgründen nicht möglich, die
Interruptroutinen des C64 durch den Emulator ausführen zu lassen,
da dann die Arbeitsgeschwindigkeit merklich nachlassen würde.
Schließlich sind gerade Interrupts eine besonders zeitkritische
Angelegenheit, da sie sehr häufig auftreten.
Damit sind nun aber alle wesentlichen Einschränkungen bei der
Emulation aufgeführt. Ein Großteil der Programme, die nicht auf
die genannten Möglichkeiten zurückgreifen, kann vom C64-Emulator
verarbeitet werden. Auch hochauflösende Grafik ist in einem
gewissen Maße möglich. Allerdings muß die Bitmap für die Grafik
im Bereich von $E000-$FFFF, also unter dem Betriebssystem liegen,
damit der Emulator erkennt, wann der Grafikspeicher angesprochen
wird. Da die Überprüfung des Bildschirmspeichers und der Bitmap
relativ viel Zeit in Anspruch nimmt, hat ein Verzicht auf diese
Ausgabekontrolle eine weitere Erhöhung der Geschwindigkeit zur
Folge.
Neben der Emulation des C64 sind auch eine Drucker- und eine
Floppy-Emulation, die der 1541 weitgehend entspricht, im Emulator
enthalten. Das Programm läuft übrigens in niedriger und in hoher
Auflösung, so daß jeder ST-Besitzer sich nun seinen eigenen C64
von Disk laden kann.